﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BaseCardTypes = Wormhole.Engine.CardLibrary.BaseCardTypes;
using CardTypes = Wormhole.Engine.CardLibrary.CardTypes;

namespace Wormhole.Engine.Decks
{
	/// <author>Rodney McKay</author>
	/// <date>09 April 2008</date>
	/// <summary>
	/// This deck hold cards in the players hand.
	/// </summary>
	public class HandCards : Deck
	{
		#region Delegates
		/// <summary>
		/// The delegate for the event that is raised when the card is played.
		/// </summary>
		public delegate void CardPlayedDelegate(BaseCardTypes.Card card);

		/// <summary>
		/// The delegate for the play allowed event.
		/// </summary>
		/// <param name="cards">A collection of cards that may be played from the hand.</param>
		public delegate void PlayAllowedDelegate(Deck cards);

		/// <summary>
		/// The delegate for the event that is raised to indicate that the player may not play cards from his hand.
		/// </summary>
		public delegate void PlayDisallowedDelegate();
		#endregion

		#region Events
		/// <summary>
		/// The event that is raised when the card is played.
		/// </summary>
		public event CardPlayedDelegate CardPlayed;

		/// <summary>
		/// This event is raised when an event card is played.
		/// </summary>
		public event CardPlayedDelegate EventPlayed;

		/// <summary>
		/// This is event is raised when a support card (character, gear, etc) is played.
		/// </summary>
		public event CardPlayedDelegate SupportPlayed;

		/// <summary>
		/// This event is raised when an adversary is played.
		/// </summary>
		public event CardPlayedDelegate AdversaryPlayed;

		/// <summary>
		/// This event is raised when an obstacle is played.
		/// </summary>
		public event CardPlayedDelegate ObstaclePlayed;

		/// <summary>
		/// This event is raised when the player is allowed to play cards from the hand.
		/// </summary>
		public event PlayAllowedDelegate PlayAllowed;

		/// <summary>
		/// This event is raised when the player is not allowed to play cards from the hand.
		/// </summary>
		public event PlayDisallowedDelegate PlayDisallowed;
		#endregion

		#region Properties

		#endregion

		#region Constructor
		/// <summary>
		/// Initialize a default instance of the class.
		/// </summary>
		public HandCards() : base()
		{
		}

		/// <summary>
		/// Create a new deck for a specific player.
		/// </summary>
		/// <param name="player">The player the deck belongs to.</param>
		public HandCards(Player.Player player) : base(player)
		{
		}
		#endregion

		#region Add
		/// <summary>
		/// Add a card to the deck and wire up events for the card.
		/// </summary>
		/// <param name="card">The card that should be added.</param>
		public override void Add(BaseCardTypes.Card card)
		{
			// add the card
			base.Add(card);

			// wire up the card events
			card.CardPlayed += new BaseCardTypes.Card.CardPlayedDelegate(card_CardPlayed);
		}
		#endregion

		#region Remove
		/// <summary>
		/// Remove a card from the library
		/// </summary>
		/// <param name="card">The card to be removed.</param>
		/// <returns>Return true if the card was removed.</returns>
		public override bool Remove(Wormhole.Engine.CardLibrary.BaseCardTypes.Card card)
		{
			// remove the event handler
			card.CardPlayed -= new BaseCardTypes.Card.CardPlayedDelegate(card_CardPlayed);

			// remove the card
			return base.Remove(card);
		}
		#endregion

		#region Set Player Events
		/// <summary>
		/// Wire up the events from other engine objects to listen for.
		/// </summary>
		protected override void SetEngineEvents()
		{
			this.Player.Deck.CardTaken += new CardTakenDelegate(Deck_CardTaken);
		}
		#endregion

		#region On Play Card
		/// <summary>
		/// Raise the event that a card was played.
		/// </summary>
		/// <param name="card">The card that was played.</param>
		protected void OnCardPlayed(BaseCardTypes.Card card)
		{
			if (this.CardPlayed != null)
				this.CardPlayed(card);

			if (card is CardTypes.Event)
				this.OnEventPlayed(card as CardTypes.Event);
			else if (card is CardTypes.Adversary)
				this.OnAdversaryPlayed(card);
			else if (card is CardTypes.Obstacle)
				this.OnObstaclePlayed(card);
			else
				this.OnSupportPlayed(card);

		}
		#endregion

		#region On Event Played
		/// <summary>
		/// Raise an event to indicate that an event card was played.
		/// </summary>
		/// <param name="card">The card that was played.</param>
		protected void OnEventPlayed(CardTypes.Event card)
		{
			if (this.EventPlayed != null)
				this.EventPlayed(card);
		}
		#endregion

		#region On Support Played
		/// <summary>
		/// Raise the event that a support was played.
		/// </summary>
		/// <param name="card">The card that was played.</param>
		protected void OnSupportPlayed(BaseCardTypes.Card card)
		{
			if (this.SupportPlayed != null)
				this.SupportPlayed(card);
		}
		#endregion

		#region On Adversary Played
		/// <summary>
		/// Raise the event that a adversary was played.
		/// </summary>
		/// <param name="card">The card that was played.</param>
		protected void OnAdversaryPlayed(BaseCardTypes.Card card)
		{
			if (this.AdversaryPlayed != null)
				this.AdversaryPlayed(card);
		}
		#endregion

		#region On Obstacle Played
		/// <summary>
		/// Raise the event that a obstacle was played.
		/// </summary>
		/// <param name="card">The card that was played.</param>
		protected void OnObstaclePlayed(BaseCardTypes.Card card)
		{
			if (this.ObstaclePlayed != null)
				this.ObstaclePlayed(card);
		}
		#endregion

		#region Event Handlers

		#region Card Taken
		/// <summary>
		/// When a card is take from the deck, place it in the players hand.
		/// </summary>
		/// <param name="card">The card that was taken.</param>
		protected void Deck_CardTaken(Wormhole.Engine.CardLibrary.BaseCardTypes.Card card)
		{
			this.Add(card);
		}
		#endregion

		#region Play Card
		/// <summary>
		/// The event handler that fires when a card is played.
		/// </summary>
		/// <param name="card">The card to play</param>
		private void card_CardPlayed(BaseCardTypes.Card card)
		{
			this.OnCardPlayed(card);
		}
		#endregion

		#endregion

		#region Set Allow Play
		/// <summary>
		/// Set the allow play property and raise the appropriate event.
		/// </summary>
		/// <param name="allow">Should cards be playable from the hand?</param>
		public void SetAllowPlay(bool allow)
		{
			// set status of the cards
			foreach (BaseCardTypes.Card card in this)
			{
				if (allow)
					card.InputStatus = BaseCardTypes.InputStatus.AllowPlay;
				else
					card.InputStatus = BaseCardTypes.InputStatus.Unavailable;
			}

			// raise the appropriate event
			if (allow)
				this.OnPlayAllowed();
			else
				this.OnPlayDisallowed();
		}
		#endregion

		#region On Play Allowed
		/// <summary>
		/// Get the cards that the player may play and raise the event.
		/// </summary>
		protected void OnPlayAllowed()
		{
			if (this.PlayAllowed != null)
			{
				Deck allowedCards = this.GetPlayableCards();
				this.PlayAllowed(allowedCards);
			}
		}
		#endregion

		#region On Play Disallowed
		/// <summary>
		/// Raise the play disallowed event.
		/// </summary>
		protected void OnPlayDisallowed()
		{
			if (this.PlayDisallowed != null)
				this.PlayDisallowed();
		}
		#endregion

		#region Get Playable Cards
		/// <summary>
		/// Get a list of cards that the player may play from his hand.
		/// </summary>
		/// <returns>A collection of cards that may be played from the hand.</returns>
		protected Decks.Deck GetPlayableCards()
		{
			Decks.Deck deck = new Decks.Deck();

			foreach (BaseCardTypes.Card card in this)
			{
				if (card.CanPlay())
					deck.Add(card);
			}

			return deck;
		}
		#endregion
	}
}
